Skip to content

feat: align the CLI with the current cloud API and expose its full surface#85

Merged
guyb1 merged 1 commit into
mainfrom
feat/api-alignment
Jul 3, 2026
Merged

feat: align the CLI with the current cloud API and expose its full surface#85
guyb1 merged 1 commit into
mainfrom
feat/api-alignment

Conversation

@guyb1

@guyb1 guyb1 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What

Aligns the CLI with the current cloud /v1 API — fixing every silent-breakage found by a deep drift audit — and exposes the full API surface as commands, verified route by route across all 70 call sites.

Silent breakage fixed

  1. org rules permissions get printed zero-valued garbage — the server's layered {defaults, byAgent} shape is now decoded (with a flat-shape fallback so older servers are never silently empty either). ⚠️ Output-shape change, called out below.
  2. apps configure silently saved nothing for github-app — the hardcoded clientId/clientSecret struct is replaced by repeatable --field key=value + --json (the old flags remain as OAuth sugar); dry-run previews mask all values.
  3. Valid rule actions rejected, conditions impossiblemanual_approval/allow accepted; --conditions (JSON array, key field included) on create/update, '[]' clears.
  4. rules update printed an all-empty rule — PATCH-then-re-fetch now prints the real rule.
  5. Server error messages were eaten — the {error:{message,type}} envelope is parsed (then flat, then status text); 403 → exit code 5 = forbidden, documented in the agent-facing skill + CLAUDE.md.
  6. --project was a silent no-op — the CLI resolves slug→id via /v1/projects and sends X-Project-Id (keeping the legacy ?projectId= for old /api servers), passing values through as-is when unresolvable so bad selections fail loudly.
  7. org rules create/update --agent-id silently discarded (org rules are agent-less server-side) — flags removed; --json payloads carrying agentId fail loudly with a pointer to the project command.
  8. Decodes no longer drop agent-relevant fields: rule metadata (distinguish app-permission rows), secret valueSource/opRef/scope/metadata + path-injection configs + 1Password fields in --json inputs, connection scope (both scopes), app credentialStubs, org config settings, and project apiKey — returned exactly once at create and previously lost unrecoverably.

Connections migration (backward compatible)

Project connections move to the top-level GET/PATCH/DELETE /v1/connections (?provider= filter, bare array) via a probe-once fallback mirroring the existing /v1-vs-/api prefix probe — older deployments transparently keep using the byte-stable legacy paths. Org connections use /v1/org/connections directly (served by every deployed server). apps list/get adopt the connections[] multi-account array.

New capabilities (everything the API serves)

rules permissions get/set (project, --agent-id + inherit), rules overlap (both scopes), apps permission-definition (tool catalog), apps connections list/rename, apps config get/toggle, apps configured / env-defaults, apps blocklist ×5 (both scopes), agents set-default / granular-access / connections get/set, org connections rename, org settings get/set, vaults list, counts, auth update. All follow the agent-first contract (--dry-run/--fields/--quiet, JSON-only stdout) and are in the machine-readable onecli help catalog (which also had its stale entries corrected).

Deliberately excluded (with reason)

Browser OAuth flows (authorize/callback/connect — popup redirects), gateway-url/gateway/ca (the CLI receives the CA inside container-config), agentless credential-stubs variant, and all cookie-gated web surfaces (session, billing, team, onboarding, partner, internal).

Breaking (output shape)

org rules permissions get output changes from a flat map to the layered {defaults, byAgent} object. The previous output was unusable zero-values (silently broken since the server-side shape change), so this is a bug fix in contract clothing.

Cloud-side follow-ups (filed, not in this repo)

  1. X-Project-Id for project keys: the cloud honors the header only for org keys; project keys always scope to their bound project. Until a small server change honors it (via the existing canAccessProjectAsUser check), --project is fully effective only for org-key callers — never silent, though: unresolvable selections now fail loudly.
  2. rules update cannot clear method (schema accepts only null, which omitempty can't emit) — server should accept "" like it does for pathPattern.

Verification

  • go build / go vet / go test ./... (+ -race on api and cmd) / golangci-lint run → all green, 0 lint issues.
  • New table-driven tests: error-envelope parsing (all branches), slug→header resolution + legacy-server fallback, connections probe (both outcomes), layered permissions decode, arbitrary-field configure passthrough, conditions round-trip (in the PATCH body), =-containing field values, both enum tables.
  • Route-by-route double-check before push: (a) completeness — all ~91 consumer-relevant server routes classified covered/excluded-with-reason (one gap found → auth update); (b) correctness — an exhaustive 70-call-site matrix, field-by-field against the zod schemas and response selects (including the untouched secrets/projects/user/run surfaces): 66 byte-exact, the rest fixed above.

Review

Full pipeline (understand → plan approval → implement → review → route-by-route double-check). Skills: ~43 enumerated across both repos, 5 applied — the repo's own agent-first-cli (help-catalog fix + dry-run/fields/quiet contracts), golang-patterns + golang-pro read in full and walked as checklists (doc-comments fix; error-wrapping/context/receivers/zero-value/no-goroutine rules verified item by item), security-review (masked previews, no secret echo), simplify (shared blocklist runners, shared field builder). Process: three adversarial agents — deep drift audit (57 tool calls), Go-idioms + contract review (71 calls), and the final exhaustive alignment matrix (64 calls) — plus hunk-level self-review. Findings → fixes: 21 total across all passes. Gates green throughout.

🤖 Generated with Claude Code

…rface

A route-by-route audit against the cloud /v1 API found silent breakage
and a season of server capabilities with no CLI exposure. This aligns
everything and verifies it call site by call site (70 total).

Fixes:
- org rules permissions get printed zero-valued garbage: the server
  moved to the layered {defaults, byAgent} shape; the CLI now decodes
  it (with a flat-shape fallback for older servers)
- apps configure only ever sent clientId/clientSecret, silently saving
  nothing for github-app; it now sends arbitrary --field key=value
  pairs (or --json), validated server-side per app
- rule actions manual_approval and allow were rejected client-side and
  conditions could not be sent at all; both supported now
- rules update decoded {success:true} into an empty rule; it now
  re-fetches and prints the real rule (incl. conditions and metadata)
- server error envelopes ({error:{message,type}}) were unreadable -
  messages surfaced now; 403 maps to exit code 5 (documented)
- --project resolved nothing server-side: the CLI now resolves
  slug->id and sends X-Project-Id (plus legacy ?projectId=); NOTE the
  cloud only honors the header for org keys today - server follow-up
  filed to honor it for project keys
- org rules create/update --agent-id was silently discarded by the
  server (org rules are agent-less); the flags are gone and JSON
  payloads carrying agentId fail loudly
- response decodes no longer drop fields agents need: rule metadata,
  secret valueSource/opRef/scope, connection scope, project apiKey
  (returned exactly once at create and previously lost), app config
  settings, credential stubs, path-injection configs

Connections move to the top-level /v1/connections resource via a
probe-once fallback (older deployments keep working on the legacy
/v1/apps/connections paths); /v1/org/connections is used directly.

New commands: rules permissions get/set (with --agent-id and the
inherit setting), rules overlap (both scopes), apps
permission-definition, apps connections list/rename, apps config
get/toggle, apps configured/env-defaults, apps blocklist (both
scopes), agents set-default/granular-access/connections get/set,
org connections rename, org settings get/set, vaults list, counts,
auth update. The machine-readable help catalog covers all of them.

BREAKING (output shape): org rules permissions get now prints the
layered object; the previous output was unusable zero-values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@guyb1
guyb1 merged commit 5d5a0c8 into main Jul 3, 2026
2 checks passed
@guyb1
guyb1 deleted the feat/api-alignment branch July 3, 2026 21:58
@guyb1 guyb1 mentioned this pull request Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant